﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Xml;
using HtmlAgilityPack;
using MALRECrewrite.Etc;
using MALRECrewrite.Models;
using MartinsEssentials.MVVM;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace MALRECrewrite.ViewModels
{
    public class ViewModel : ViewModelBase
    {
        #region props

        private double _DownloadRecommendationsProgress = 1;
        public double DownloadRecommendationsProgress
        {
            get
            {
                return _DownloadRecommendationsProgress;
            }
            set
            {
                if (value != _DownloadRecommendationsProgress)
                {
                    _DownloadRecommendationsProgress = value;
                    OnPropertyChanged("DownloadRecommendationsProgress");
                    OnPropertyChanged("IsDownloadingData");
                    SetW7Progress();
                }
            }
        }

        private double _DownloadHighResPicturesProgress = 1;
        public double DownloadHighResPicturesProgress
        {
            get
            {
                return _DownloadHighResPicturesProgress;
            }
            set
            {
                if (value != _DownloadHighResPicturesProgress)
                {
                    _DownloadHighResPicturesProgress = value;
                    OnPropertyChanged("DownloadHighResPicturesProgress");
                    OnPropertyChanged("IsDownloadingData");
                    SetW7Progress();
                }
            }
        }

        private double _DownloadGenresProgress = 1;
        public double DownloadGenresProgress
        {
            get
            {
                return _DownloadGenresProgress;
            }
            set
            {
                if (value != _DownloadGenresProgress)
                {
                    _DownloadGenresProgress = value;
                    OnPropertyChanged("DownloadGenresProgress");
                    OnPropertyChanged("IsDownloadingData");
                    SetW7Progress();
                }
            }
        }

        public bool IsDownloadingData
        {
            get
            {
                return DownloadGenresProgress !=  1 || DownloadHighResPicturesProgress != 1 || DownloadRecommendationsProgress != 1;
            }
        }

        private bool _IsDownloadingAnimeList;
        public bool IsDownloadingAnimeList
        {
            get
            {
                return _IsDownloadingAnimeList;
            }
            set
            {
                if (value != _IsDownloadingAnimeList)
                {
                    _IsDownloadingAnimeList = value;
                    OnPropertyChanged("IsDownloadingAnimeList");
                }
            }
        }

        private bool _AreSettingsDirty = false;

        private string _Username = "martinyyyy";

        public string Username
        {
            get
            {
                return _Username;
            }
            set
            {
                if (value != _Username)
                {
                    _Username = value;
                    OnPropertyChanged("Username");
                }
            }
        }

        private bool _ShowAllInfos;

        public bool ShowAllInfos
        {
            get
            {
                return _ShowAllInfos;
            }
            set
            {
                if (value != _ShowAllInfos)
                {
                    _ShowAllInfos = value;
                    OnPropertyChanged("ShowAllInfos");

                    SortedRecommendations.ToList().ForEach(x => x.ShowAllInfo = _ShowAllInfos);
                }
            }
        }

        private bool _IsLoadingFromSave = false;

        public bool IsLoadingFromSave
        {
            get
            {
                return _IsLoadingFromSave;
            }
            set
            {
                if (value != _IsLoadingFromSave)
                {
                    _IsLoadingFromSave = value;
                    OnPropertyChanged("IsLoadingFromSave");
                }
            }
        }

        private List<Anime> _Animes;

        public List<Anime> Animes
        {
            get
            {
                return _Animes;
            }
            set
            {
                if (value != _Animes)
                {
                    _Animes = value;
                    OnPropertyChanged("Animes");
                }
            }
        }

        public Dictionary<int, List<string>> GenreCache = new Dictionary<int, List<string>>();

        private List<Genre> _Genres = new List<Genre>();

        public List<Genre> Genres
        {
            get
            {
                return _Genres;
            }
            set
            {
                if (value != _Genres)
                {
                    _Genres = value;
                    OnPropertyChanged("Genres");
                }
            }
        }

        private string _SelectedGenreMode = "or";
        public string SelectedGenreMode
        {
            get
            {
                return _SelectedGenreMode;
            }
            set
            {
                if (value != _SelectedGenreMode)
                {
                    _SelectedGenreMode = value;
                    OnPropertyChanged("SelectedGenreMode");
                }
            }
        }


        private ObservableCollection<SortedRecommendation> _SortedRecommendations;

        public ObservableCollection<SortedRecommendation> SortedRecommendations
        {
            get
            {
                return _SortedRecommendations;
            }
            set
            {
                if (value != _SortedRecommendations)
                {
                    _SortedRecommendations = value;
                    OnPropertyChanged("SortedRecommendations");
                }
            }
        }

        private ObservableCollection<SortedRecommendation> _Blacklist = new ObservableCollection<SortedRecommendation>();
        public ObservableCollection<SortedRecommendation> Blacklist
        {
            get
            {
                return _Blacklist;
            }
            set
            {
                if (value != _Blacklist)
                {
                    _Blacklist = value;
                    OnPropertyChanged("Blacklist");
                }
            }
        }

        private ObservableCollection<AnimeGroup> _AnimeGroups = new ObservableCollection<AnimeGroup>();
        public ObservableCollection<AnimeGroup> AnimeGroups
        {
            get
            {
                return _AnimeGroups;
            }
            set
            {
                if (value != _AnimeGroups)
                {
                    _AnimeGroups = value;
                    OnPropertyChanged("AnimeRoots");
                }
            }
        }

        private RecommendationComperer _recommendationComperer = new RecommendationComperer();
        private GenreComperer _genreComperer = new GenreComperer();
        private AnimeComperer _animeComperer = new AnimeComperer();

        private SortedRecommendation _SelectedRecommendation;

        public SortedRecommendation SelectedRecommendation
        {
            get
            {
                return _SelectedRecommendation;
            }
            set
            {
                if (value != _SelectedRecommendation)
                {
                    _SelectedRecommendation = value;
                    OnPropertyChanged("SelectedRecommendation");
                }
            }
        }

        private string _Message;
        public string Message
        {
            get
            {
                return _Message;
            }
            set
            {
                _Message = value;
                OnPropertyChanged("Message");
            }
        }

        #endregion props

        public async void LoadAnimeList()
        {
            // Arbeitet bereits oder kein Nutzername
            if (Username == null)
                return;

            Message = "Loading Animelist";

            Animes = null;
            SortedRecommendations = null;

            DownloadGenresProgress = 0;
            DownloadHighResPicturesProgress = 0;
            DownloadRecommendationsProgress = 0;

            await TaskEx.Run(() =>
                {
                    Animes = GetAnimeList();
                });

            LoadRecommendations();
        }

        private List<Anime> GetAnimeList()
        {
            IsDownloadingAnimeList = true;
            List<Anime> tempAnimes = new List<Anime>();

            HtmlAgilityPack.HtmlWeb web = new HtmlWeb();
            HtmlAgilityPack.HtmlDocument doc = web.Load("http://myanimelist.net/animelist/" + Username + "&status=7&order=0");

            HtmlNodeCollection hnc = doc.DocumentNode.SelectNodes("//body/div/table");

            bool nextBreak = false;
            for (int i = 3; i < hnc.Count; i++)
            {
                HtmlNode a = hnc[i].SelectSingleNode("tr");
                if (!a.InnerHtml.Contains("category_totals"))
                {
                    HtmlNode name = a.Descendants("a").Where(tr => tr.GetAttributeValue("class", "") == "animetitle").SelectMany(tr => tr.Descendants("span")).ToArray()[0];
                    string link = a.Descendants("a").Where(tr => tr.GetAttributeValue("class", "") == "animetitle").Select(tr => tr.GetAttributeValue("href", "")).ToArray()[0];
                    string score = a.Descendants("td").Where(tr => tr.GetAttributeValue("width", "") == "45").Select(tr => tr.InnerText).ToArray()[0];

                    Anime anime = new Anime();
                    anime.Title = name.InnerText;
                    anime.Aid = int.Parse(link.Replace("http://myanimelist.net/anime/", "").Split('/')[0]);
                    anime.Uri = link + "/userrecs";
                    anime.IsDropped = nextBreak;
                    anime.IsActive = true;

                    int blub;
                    if (int.TryParse(score, out blub))
                        anime.Score = blub;
                    else
                        anime.Score = 0;

                    tempAnimes.Add(anime);
                }
                else
                {
                    if (nextBreak)
                        break;

                    if (hnc[i + 1].InnerText.Contains("Dropped"))
                        nextBreak = true;

                    i += 2;
                }
            }

            IsDownloadingAnimeList = false;
            return tempAnimes.OrderBy(x => x.Title).ToList();
        }

        public async Task LoadRecommendations(bool onlyUpdate = false)
        {
            List<Task> tasks = new List<Task>();
            var activeAnimes = Animes.Where(a => a.IsActive);

            if (onlyUpdate)
            {
                activeAnimes = activeAnimes.Where(x => !x.DataDownloaded);
            }

            double recommendationsCount = activeAnimes.Count();
            double currentDownloadProgress = 0;

            DownloadRecommendationsProgress = 0;

            foreach (Anime anime in activeAnimes)
            {
                Task tempTask = GetRecommendations(anime);
                tempTask.ContinueWith(delegate
                    {
                        _AreSettingsDirty = true;
                        currentDownloadProgress++;
                        DownloadRecommendationsProgress = currentDownloadProgress / recommendationsCount;
                    });
                tasks.Add(tempTask);

                if (tasks.Count > 5)
                {
                    await TaskEx.WhenAny(tasks);
                    tasks.RemoveAll(x => x.IsCompleted);

                    if (currentDownloadProgress % 5 == 0)
                        SortAnimeRecommendations();
                }
            }

            await TaskEx.WhenAll(tasks);
            await SortAnimeRecommendations();

            CheckOutstandingData();
        }

        private Task GetRecommendations(Anime anime)
        {
            anime.Recommendations.Clear();

            WebClient wc = new WebClient();
            wc.Encoding = System.Text.Encoding.UTF8;

            var tempAnime = anime;
            var downloadTask = wc.DownloadStringTaskAsync(new Uri(anime.Uri));
            var continuation = downloadTask.ContinueWith(delegate
            {
                HtmlAgilityPack.HtmlDocument recDoc = new HtmlDocument();
                recDoc.LoadHtml(downloadTask.Result);
                HtmlNodeCollection recHnc = recDoc.DocumentNode.SelectNodes("//body");

                foreach (HtmlNode h in recHnc)
                {
                    HtmlNode[] nodes = h.Descendants("div").Where(tr => tr.GetAttributeValue("id", "").Contains("raArea")).ToArray();
                    foreach (HtmlNode p in nodes)
                    {
                        string score = "0";
                        string image = "";
                        string name = p.ParentNode.ChildNodes[3].SelectSingleNode(p.ParentNode.ChildNodes[3].XPath + "/a").InnerText;
                        HtmlNode blub = p.ParentNode.ChildNodes[3].SelectSingleNode(p.ParentNode.ChildNodes[3].XPath + "/a");
                        string haha = blub.GetAttributeValue("href", "");

                        var img = p.SelectSingleNode(p.ParentNode.ParentNode.ChildNodes[1].XPath + "/div[1]/a[1]/img[1]");
                        if (img != null)
                        {
                            image = img.GetAttributeValue("src", "");
                            //     image = image.Replace("t.jpg",".jpg");
                        }

                        if (p.ParentNode.ChildNodes.Count >= 8)
                        {
                            score = p.ParentNode.ChildNodes[7].SelectSingleNode(p.ParentNode.ChildNodes[7].XPath + "/a/strong").InnerText;
                        }

                        int aid = int.Parse(haha.Replace("http://myanimelist.net/anime/", "").Split('/')[0]);

                        tempAnime.Recommendations.Add(new Recommendation()
                        {
                            Count = int.Parse(score) + 1,
                            Title = name,
                            Uri = haha,
                            Image = image,
                            Aid = aid,
                            ParentAid = anime.Aid
                        });

                        if (GenreCache.ContainsKey(aid))
                            tempAnime.Recommendations.Last().Genres = GenreCache[aid];
                    }
                }

                anime.DataDownloaded = true;
            });

            return continuation;
        }

        public async Task GetHighResThumbs()
        {
            string filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"MALRECRewrite\Images\");

            if (!Directory.Exists(filepath))
                Directory.CreateDirectory(filepath);

            List<Task> tasks = new List<Task>();

            if (SortedRecommendations == null)
                return;

            List<SortedRecommendation> missingPictures = SortedRecommendations.Where(x => !File.Exists(filepath + x.Aid + ".jpg")).ToList();

            double completeCount = missingPictures.Count;

            if (completeCount == 0)
            {
                DownloadHighResPicturesProgress = 1;
                return;
            }
            double currentCount = 0;
            DownloadHighResPicturesProgress = 0;

            for (int i = 0, temp = 0; i < missingPictures.Count; i++, temp++)
            {
                string tempfilepath = filepath + missingPictures[i].Aid + ".jpg";

                string path = Path.GetTempFileName();

                WebClient wc = new WebClient();
                var recommendation = missingPictures[i];
                var downloadTask = wc.DownloadFileTaskAsync(new Uri(recommendation.Image.Replace("t.jpg", ".jpg")), path);
                var continuation = downloadTask.ContinueWith(delegate
                    {
                        SavePictureAsThumb(path, tempfilepath);

                        List<SortedRecommendation> sr = SortedRecommendations.Where(x => x.Aid == recommendation.Aid).ToList();
                        SortedRecommendations.Where(x => x.Aid == recommendation.Aid).ToList().ForEach(x => x.Image = tempfilepath);

                        currentCount++;
                        DownloadHighResPicturesProgress = currentCount / completeCount;
                    });

                tasks.Add(continuation);

                if (temp == 5)
                {
                    await TaskEx.WhenAll(tasks);
                    temp = 0;
                }
            }

            await TaskEx.WhenAll(tasks);
            DownloadHighResPicturesProgress = 1;
        }

        private void SavePictureAsThumb(string source, string target)
        {
            System.Drawing.Image image = System.Drawing.Image.FromFile(source);

            image = image.GetThumbnailImage(120, (int)((double)image.Height * (120.0 / image.Width)), null, IntPtr.Zero);
            image.Save(target);
        }

        public async Task GetMALStats()
        {
            List<Task> tasks = new List<Task>();

            if (SortedRecommendations == null)
                return;

            double completeCount = SortedRecommendations.Count(x => !GenreCache.Keys.Contains(x.Aid));

            if (completeCount == 0)
            {
                DownloadGenresProgress = 1;
                return;
            }
            
            double currentCount = 0;
            DownloadGenresProgress = 0;

            foreach (SortedRecommendation sr in SortedRecommendations.Where(x => !GenreCache.Keys.Contains(x.Aid)))
            {
                WebClient wc = new WebClient();
                var recommendation = sr;
                var downloadTask = wc.DownloadStringTaskAsync(new Uri("http://mal-api.com/anime/" + sr.Aid + "?format=xml"));
                var continuation = downloadTask.ContinueWith(delegate
                {
                    XmlDocument x = new XmlDocument();
                    x.LoadXml(downloadTask.Result);

                    XmlNodeList xn = x.SelectNodes("/anime/genre");

                    List<string> genres = new List<string>();
                    foreach (XmlNode z in xn)
                        genres.Add(z.InnerText);

                    if (genres != null)
                    {
                        if (GenreCache.ContainsKey(recommendation.Aid))
                            GenreCache[recommendation.Aid] = genres;
                        else
                            GenreCache.Add(recommendation.Aid, genres);

                        var q = SortedRecommendations.Where(y => y.Aid == recommendation.Aid);
                        if (q.Count() > 0)
                            q.First().Genres = genres;
                    }

                    currentCount++;
                    DownloadGenresProgress = currentCount / completeCount;

                    _AreSettingsDirty = true;
                });

                tasks.Add(continuation);

                if (tasks.Count > 5)
                {
                    await TaskEx.WhenAny(tasks);
                    tasks.RemoveAll(x => x.IsCompleted);

                    List<string> tempGenres = new List<string>();
                    for (int i = 0; i < GenreCache.Count; i++)
                    {
                        try
                        {
                            tempGenres = GenreCache.ElementAt(i).Value.Union(tempGenres).ToList();
                        }
                        catch (Exception)
                        {
                            continue;
                        }
                    }

                    List<Genre> temp2 = new List<Genre>();
                    tempGenres.ForEach(x => temp2.Add(new Genre() { Name = x, IsEnabled = true }));
                    var q = Genres.Union(temp2, _genreComperer).OrderBy(x => x.Name).ToList();
                    if (q.Count != Genres.Count)
                    {
                        Genres = q;
                    }
                }
            }

            await TaskEx.WhenAll(tasks);
            List<string> tempGenres2 = new List<string>();
            for (int i = 0; i < GenreCache.Count; i++)
            {
                    tempGenres2 = GenreCache.ElementAt(i).Value.Union(tempGenres2).ToList();
            }

            List<Genre> temp22 = new List<Genre>();
            tempGenres2.ForEach(x => temp22.Add(new Genre() { Name = x, IsEnabled = true }));
            var qw = Genres.Union(temp22, _genreComperer).OrderBy(x => x.Name).ToList();
            if (qw.Count != Genres.Count)
            {
                Genres = qw;
                _AreSettingsDirty = true;
            }

            DownloadGenresProgress = 1;
        }

        public void Save()
        {
            //if (_AreSettingsDirty)
                new DataSaver().SaveData(this);
        }

        public async Task Load()
        {
            if (await new DataSaver().LoadData(this))
            {
                await SortAnimeRecommendations();
                CheckOutstandingData();
                //CheckAnimeListForNewSeasons();
            }
            else
            {
                IsLoadingFromSave = false;
                LoadAnimeList();
            }
        }

        public async void CheckOutstandingData()
        {
            _AreSettingsDirty = true;

            DownloadRecommendationsProgress = 0;
            DownloadHighResPicturesProgress = 0;
            DownloadGenresProgress = 0;

            if (Animes.Count(x => !x.DataDownloaded) > 0)
                LoadRecommendations(true);
            else
            {
                Task[] tasks = new Task[] { GetHighResThumbs(), GetMALStats() };
                DownloadRecommendationsProgress = 1;

                await TaskEx.WhenAll(tasks);
            }
        }

        public async Task SortAnimeRecommendations(bool orderGenres = true)
        {
            if (orderGenres)
            {
                List<string> tempGenres = new List<string>();

                await TaskEx.Run(() =>
                    {
                        foreach (KeyValuePair<int, List<string>> kvp in GenreCache)
                        {
                            tempGenres = kvp.Value.Union(tempGenres).ToList();
                        }
                    });

                List<Genre> tempGenre = new List<Genre>();
                tempGenres.OrderBy(x => x).ToList().ForEach(x => tempGenre.Add(new Genre() { Name = x, IsEnabled = true }));
                Genres = tempGenre;
            }

            IOrderedEnumerable<SortedRecommendation> temp = null;

            await TaskEx.Run(() =>
                {
                    List<Recommendation> recommendations = new List<Recommendation>();

                    Animes.Where(x => x.IsActive).Select(x => x.Recommendations).ToList().ForEach(x => recommendations.AddRange(x));

                    temp = (
                            from r in recommendations
                            where !Animes.Select(x => x.Title).Contains(r.Title) && !Blacklist.Contains(r,_recommendationComperer)
                            group r by r.Title into g
                            select new SortedRecommendation(g.First())
                            {
                                CountSum = g.Sum(x => x.Count),
                                SourceSum = g.Count(),
                                Genres = GenreCache.ContainsKey(g.First().Aid) ? GenreCache[g.First().Aid] : new List<string>(),
                                Sources = new ObservableCollection<string>(Animes.Where(h=>g.Select(x=>x.ParentAid).Contains(h.Aid)).Select(x=>x.Title))
                            }
                        ).ToList().OrderByDescending(x => x.CountSum);
                });
            SortedRecommendations = new ObservableCollection<SortedRecommendation>(temp);
        }

        public async void SortRecommendationsByGenre()
        {
            await SortAnimeRecommendations(false);

            if(SelectedGenreMode == "or")
            {
                List<string> deactivatedGenres = Genres.Where(x => !x.IsEnabled).Select(x => x.Name).ToList();
                SortedRecommendations = new ObservableCollection<SortedRecommendation>(SortedRecommendations.Where(x => x.Genres.Except(deactivatedGenres).Count() != 0));
            }
            else
            {
                List<string> activatedGenres = Genres.Where(x => x.IsEnabled).Select(x => x.Name).ToList();
                SortedRecommendations = new ObservableCollection<SortedRecommendation>(SortedRecommendations.Where(x => x.Genres.Intersect(activatedGenres).Count() == activatedGenres.Count));
            }
        }

        public async void UpdateAnimeList()
        {
            List<Anime> toAddAnimes = new List<Anime>();
            Message = "Updating";
            bool hasChanged = false;


            await TaskEx.Run(delegate
            {
                List<Anime> newAnimeList = GetAnimeList();

                if (!((newAnimeList.Count == Animes.Count) && !newAnimeList.Except(Animes, _animeComperer).Any()))
                {
                    DownloadGenresProgress = 0;
                    DownloadHighResPicturesProgress = 0;
                    DownloadRecommendationsProgress = 0;

                    var toDeleteAnimes = Animes.Except(newAnimeList, _animeComperer);
                    Animes.RemoveAll(x => toDeleteAnimes.Contains(x, _animeComperer));

                    toAddAnimes = newAnimeList.Except(Animes, _animeComperer).ToList();

                    _AreSettingsDirty = true;

                    Message = toAddAnimes.Count + " new "+ (toAddAnimes.Count == 1 ? "Anime" : "Animes");

                    hasChanged = true;
                }
                else
                {
                    Message = "No new Animes found";
                }
            });

            if (!hasChanged)
                return;

            Animes = Animes.Union(toAddAnimes).OrderBy(h=>h.Title).ToList();

            double complete = toAddAnimes.Count;
            double current = 0;

            foreach (Anime anime in toAddAnimes)
            {
                Task k = GetRecommendations(anime);
                await k;

                current++;
                DownloadRecommendationsProgress = current / complete;
            }

            await SortAnimeRecommendations();
            CheckOutstandingData();
        }

        public void SetW7Progress()
        {
            double progress = (DownloadGenresProgress / 3) + (DownloadHighResPicturesProgress / 3) + (DownloadRecommendationsProgress / 3);

            Microsoft.WindowsAPICodePack.Taskbar.TaskbarManager tbManager = Microsoft.WindowsAPICodePack.Taskbar.TaskbarManager.Instance;

            if (progress < 1)
            {
                tbManager.SetProgressState(Microsoft.WindowsAPICodePack.Taskbar.TaskbarProgressBarState.Normal);
                tbManager.SetProgressValue((int)(progress * 100.0), 100);
            }
            else
                tbManager.SetProgressState(Microsoft.WindowsAPICodePack.Taskbar.TaskbarProgressBarState.NoProgress);
        }

        public void AddToBlacklist()
        {
            if (SelectedRecommendation != null)
            {
                Blacklist.Add(SelectedRecommendation);
            }

            SortedRecommendations.Remove(SelectedRecommendation);

            _AreSettingsDirty = true;
        }

        public async void RemoveFromBlacklist(Recommendation r)
        {
            if(Blacklist.Where(x=>x.Title == r.Title).Count() > 0)
                Blacklist.Remove(Blacklist.Where(x => x.Title == r.Title).First());
            await SortAnimeRecommendations();

            _AreSettingsDirty = true;
        }

        private bool _languagesAlreadyLoading = false;
        private int _langaugesQuery = 0;
        public async void GetNext10Langauges()
        {
            if (_languagesAlreadyLoading)
            {
                _langaugesQuery += 10;
                Message = "Added another 10 Languages to query";
                return;
            }

            Message = "Loading 10 Languages";
            _languagesAlreadyLoading = true;

            do
            {
                int counts = 0;
                foreach (SortedRecommendation sr in SortedRecommendations.Where(x => !x.IsEnglish && !x.IsGerman && !x.LangUnknown && !x.IsJapanese).Take(10))
                {
                    await GetLanguagesFromAniSearch(sr);
                    counts++;
                }

                if (counts == 0)
                    break;

                _langaugesQuery -= 10;
            }
            while (_langaugesQuery > 0);

            _languagesAlreadyLoading = false;
            Message = "Queried Languages loaded";
        }

        public async Task GetLanguagesFromAniSearch(SortedRecommendation a)
        {
            if (a.IsEnglish || a.IsGerman || a.LangUnknown || a.IsJapanese)
                return;

            var temp = a;
            await TaskEx.Run(() =>
                {
                    string result = GetHtmlPageFromAniSearch(temp.Title);
                    if (!IsRegexMatch(result, temp))
                    {
                        if (result.Contains(@"<div class=""xhead""><strong>Treffer</strong>"))
                        {
                            string utf8Result = Encoding.UTF8.GetString(Encoding.GetEncoding("ISO-8859-1").GetBytes(result));

                            string cleanTitle = HTMLCharacterConverter.Purge(temp.Title);

                            string[] splitted = cleanTitle.Split(' ');
                            string ss = @"<span class=""highlight"">" + Regex.Escape(splitted[0]) + "</span>";


                            var c = Regex.Match(utf8Result, @"<a href=""forward\.php\?id=(.*?)"">" + ss);

                            if (!c.Success)
                            {
                                c = Regex.Match(utf8Result, @"<a href=""forward\.php\?id=(.*?)"">" + Regex.Escape(cleanTitle));
                            }

                            if (c.Success)
                            {
                                string s = new WebClient().DownloadString("http://anisearch.de/index.php?page=anime&id=" + c.Groups[1]);
                                if (!IsRegexMatch(s, temp))
                                {
                                    temp.LangUnknown = true;
                                }
                            }
                            else
                                temp.LangUnknown = true;
                        }
                        else
                            temp.LangUnknown = true;
                    }
                });
        }

        private bool IsRegexMatch(string result, SortedRecommendation a)
        {
            result = result.Replace(System.Environment.NewLine, "");

            var m = Regex.Match(result, @"<td valign=""top"" class=""atitle1"">Erh&auml;ltlich in</td>					<td class=""acontent1"">(.*?)</td>");
            if (m.Success)
            {
                a.IsGerman = m.Groups[1].Value.Contains("Deutsch");
                a.IsEnglish = m.Groups[1].Value.Contains("Englisch");

                a.LangUnknown = false;
            }
            else if (result.Contains("<td valign=\"top\" class=\"atitle1\">Original</td>"))
            {
                a.IsJapanese = true;
                a.LangUnknown = false;
                return true;
            }
            
            return m.Success;
        }

        private string GetHtmlPageFromAniSearch(string title)
        {
            title = HttpUtility.UrlEncode(title,Encoding.Unicode);

            var encoding = new UTF8Encoding();
            var postData = "qsearch=" + title;
            //postData += ("&username=" + strName);
            byte[] data = encoding.GetBytes(postData);

            var myRequest =
              (HttpWebRequest)WebRequest.Create("http://anisearch.de/?page=suche&mode=anime");
            myRequest.Method = "POST";
            myRequest.ContentType = "application/x-www-form-urlencoded";
            myRequest.ContentLength = data.Length;
            var newStream = myRequest.GetRequestStream();
            newStream.Write(data, 0, data.Length);
            newStream.Close();

            var response = myRequest.GetResponse();
            var responseStream = response.GetResponseStream();
            var responseReader = new StreamReader(responseStream);
            return responseReader.ReadToEnd();
        }

        public async void GenerateAnimeGroups()
        {
            foreach (Anime a in Animes)
            {
                a.ChildElementAids = await App.SequelsModel.GetChildNodesOfAnime(a);
            }

            AnimeGroups.Clear();
            foreach (Anime a in Animes.Where(x => !x.IsSequel))
            {
                if (a.Children.Count == 0)
                {
                    AnimeGroups.Add(new AnimeGroup(a.Title, a));
                }
                else
                {
                    AnimeGroup ag = new AnimeGroup(a.Title, null);
                    ag.Children.Add(new AnimeGroup(a.Title, a, ag));
                    a.Children.ToList().ForEach(x => ag.Children.Add(new AnimeGroup(x.Title, x, ag)));
                    AnimeGroups.Add(ag);
                }
            }
        }

        #region comparer classes

        private class RecommendationComperer : IEqualityComparer<Recommendation>
        {
            public bool Equals(Recommendation a1, Recommendation a2)
            {
                return a1.Title == a2.Title;
            }

            public int GetHashCode(Recommendation r)
            {
                return r.Title == null ? 0 : r.Title.GetHashCode();
            }
        }

        private class GenreComperer : IEqualityComparer<Genre>
        {
            public bool Equals(Genre a1, Genre a2)
            {
                return a1.Name == a2.Name;
            }

            public int GetHashCode(Genre r)
            {
                return r.Name == null ? 0 : r.Name.GetHashCode();
            }
        }

        private class AnimeComperer : IEqualityComparer<Anime>
        {
            public bool Equals(Anime a1, Anime a2)
            {
                return a1.Title == a2.Title;
            }

            public int GetHashCode(Anime r)
            {
                return r.Title == null ? 0 : r.Title.GetHashCode();
            }
        }

        #endregion comparer classes
    }
}